package com.youxin.cpcenter.service.impl;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.zxing.common.BitMatrix;
import com.youxin.busfoundation.Consts;
import com.youxin.busfoundation.bean.BusinessMessages;
import com.youxin.busfoundation.bean.ResponseObject;
import com.youxin.busfoundation.common.qiniu.QiniuBucketType;
import com.youxin.busfoundation.config.WxBeanConfig;
import com.youxin.busfoundation.enums.EnterpriseIdentityType;
import com.youxin.busfoundation.enums.OrderPayStatusEnums;
import com.youxin.busfoundation.enums.OrderPayTypeEnums;
import com.youxin.busfoundation.enums.PayTypeEnums;
import com.youxin.busfoundation.enums.ProductsCouponEnums;
import com.youxin.busfoundation.enums.SourceTypeEnums;
import com.youxin.busfoundation.utils.weixin.PayCommonUtil;
import com.youxin.cpcenter.bean.RequestOrderInfoBean;
import com.youxin.cpcenter.bean.ResponsePayEntranceBean;
import com.youxin.cpcenter.dao.TbMemberInfoMapper;
import com.youxin.cpcenter.model.TbMemberInfo;
import com.youxin.cpcenter.model.TbOrderInfo;
import com.youxin.cpcenter.service.TransactionService;
import com.youxin.cpcenter.service.UploadService;
import com.youxin.cpcenter.service.WxPayService;
import com.youxin.cpcenter.utils.MemberRightsUtils;
import com.youxin.foundation.db.utils.KeyGenerationUtils;
import com.youxin.foundation.utils.AmountUtils;
import com.youxin.foundation.utils.GenerateIdUtils;
import com.youxin.foundation.utils.HttpUtil;
import com.youxin.foundation.utils.QRCodeUtil;
import com.youxin.foundation.utils.StringUtils;
import com.youxin.foundation.utils.XMLUtil;

/**
 * @ClassName: WeixinPayServiceImpl
 * @Description: 微信扫码支付
 * @author yingde.cao
 * @date 2017年11月29日 上午10:03:51
 *
 */
@Service("wxPayService")
public class WeixinPayServiceImpl implements WxPayService {
	private static final Logger logger = LoggerFactory.getLogger(WeixinPayServiceImpl.class);
	private static WxBeanConfig wxBeanConfig = WxBeanConfig.getConfig();
	@Autowired
	private TbMemberInfoMapper tbMemberInfoMapper;
	@Autowired
	private TransactionService transactionService;
	@Autowired
	private UploadService uploadService;
	@Override
	/**
	 * 微信扫码支付，模式二
	 */
	public ResponseObject weixinPay2(HttpServletRequest request, HttpServletResponse response,RequestOrderInfoBean requestBean) {
		String orderSn = GenerateIdUtils.getOrderSn();
		try {	
			//是否管理员验证
			//TODO:权限整合调整 by jinwen.you requestBean.getMemberId()参数可以忽略
			TbMemberInfo memberInfo = MemberRightsUtils.isAdmin(tbMemberInfoMapper); 
			// 账号信息 // key
			String key = wxBeanConfig.getApiKey();
			// 交易类型 原生扫码支付
			String tradeType = "NATIVE";
			SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
			commonParams(packageParams);
			// 商品ID
			packageParams.put("product_id", requestBean.getProductId().toString());
			// 商品描述
			String descbody = OrderPayTypeEnums.getName(requestBean.getOrderType());
			packageParams.put("body", descbody);
			// 商户订单号
			packageParams.put("out_trade_no", orderSn.toString());
			
			// 总金额 微信用 分做单位，需要元转分
			String total_amount = "0";
			if(requestBean.getOrderType().equals(OrderPayTypeEnums.VIP.getIndex())){
				total_amount = EnterpriseIdentityType.Vip.getMemberUpgradeFee().toString();
			}else if(requestBean.getOrderType().equals(OrderPayTypeEnums.PTVIP.getIndex())){
				total_amount = EnterpriseIdentityType.Normal.getMemberUpgradeFee().toString();
			}else {
				//total_amount = requestBean.getProductId().toString();
				total_amount = "0.01";  //测试
			}
			
			// 总金额 微信用 分做单位，需要元转分
			packageParams.put("total_fee", AmountUtils.changeY2F(total_amount));
			// 发起人IP地址
			//packageParams.put("spbill_create_ip", getIp(request));
			// 回调地址
			packageParams.put("notify_url", wxBeanConfig.getNotifyUrl());
			// 交易类型
			packageParams.put("trade_type", tradeType);
			String sign = PayCommonUtil.createSign(Consts.CHARACTERE_NCODING_UTF8, packageParams, key);
			// 签名
			packageParams.put("sign", sign);

			String requestXML = PayCommonUtil.getRequestXml(packageParams);
			String resXml = HttpUtil.postData(wxBeanConfig.getUnifiedOrderUrl(), requestXML);
			Map<String,String> map = XMLUtil.doXMLParse(resXml);
			String returnCode = (String) map.get("return_code");
			if (Consts.SUCCESS_CAPITAL.equals(returnCode)) {
				String resultCode = (String) map.get("result_code");
				if (Consts.SUCCESS_CAPITAL.equals(resultCode)) {
					//保存支付请求数据
					requestBean.setPayType(PayTypeEnums.WX.getIndex());
					requestBean.setDesc(ProductsCouponEnums.getName(requestBean.getProductId())+"点");
					requestBean.setSource(SourceTypeEnums.Web.getValue());
					transactionService.procesPayTransaction(requestBean, memberInfo, orderSn);
					
					String urlCode = (String) map.get("code_url");
					// 转换为短链接
					shorturl(urlCode);
					// 生成二维码
					BitMatrix matrix = QRCodeUtil.getQRCodeImge(urlCode,300, null );
					BufferedImage image = QRCodeUtil.toBufferedImage(matrix);
					ByteArrayOutputStream out = new ByteArrayOutputStream();  
			        boolean flag = ImageIO.write(image, "png", out);
			        if(!flag){
			        	return ResponseObject.userFailure("订单号："+orderSn+"生成二维码失败");
			        }
			        byte[] data = out.toByteArray();
			        String fileName = requestBean.getProductId() + "_" + KeyGenerationUtils.generateKey() + ".png";
			        String result = uploadService.upload(QiniuBucketType.CpWxPayQrCode.getName(), data, fileName);
					String qrCodeImgUrl = QiniuBucketType.CpWxPayQrCode.getUrl() + result;
					if(StringUtils.isNullOrEmpty(qrCodeImgUrl)) {
						return ResponseObject.userFailure("订单号："+orderSn+"生成微信支付二维码(上传七牛云)失败");
					}
					ResponsePayEntranceBean rs = new ResponsePayEntranceBean();
					rs.setOrderSn(orderSn);
					rs.setPayEntrance(qrCodeImgUrl);
					return new ResponseObject(rs);
				} else {
					String errCodeDes = (String) map.get("err_code_des");
					return ResponseObject.userFailure("订单号："+orderSn+"生成微信支付码(系统)失败:"+errCodeDes+"");
				}
			} else {
				String returnMsg = (String) map.get("return_msg");
				return ResponseObject.userFailure("(订单号："+orderSn+"生成微信支付码(通信)失败:"+returnMsg+"");
			}
		} catch (Exception e) {
			return ResponseObject.systemError("订单号："+orderSn+"生成微信支付码失败(系统异常))"+e);
		}
	}
	/**
	 * 微信异步回调请求
	 */
	@Override
	public String weixinPayNotify(HttpServletRequest request) {
		TbOrderInfo model = new TbOrderInfo();
		// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
		String resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
				+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
		try {
			// 将request转Map
			SortedMap<Object, Object> packageParams = processRequestToMap(request);
			// 账号信息 // key
			String key = wxBeanConfig.getApiKey();
			// 账号信息
			// 判断签名是否正确
			if (PayCommonUtil.isTenpaySign(Consts.CHARACTERE_NCODING_UTF8, packageParams, key)) {
				logger.warn("微信支付成功回调");
				// 这里是支付成功
				if (Consts.SUCCESS_CAPITAL.equals((String) packageParams.get("result_code"))) {
					String orderSn = (String) packageParams.get("out_trade_no");
					//微信返回交易ID
					String tradeNo = (String) packageParams.get("transaction_id");
					String payAmount = (String) packageParams.get("total_fee");
					model.setOrderSn(orderSn);
					model.setPlatformNo(tradeNo);
		            BigDecimal pa=new BigDecimal(AmountUtils.changeF2Y(payAmount));
		            model.setPayAmount(pa);
		            model.setPayStatus(OrderPayStatusEnums.PaySuccess.getValue());
		            logger.warn("微信支付订单号{}付款成功", orderSn);
				} else {
					logger.warn("支付失败,错误信息：{}", packageParams.get("err_code"));
					model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
				}
			} else {
				logger.warn("通知签名验证失败");
				model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
			}
		} catch (Exception e) {
			logger.warn("处理微信回调系统错误，msg="+e);
			model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
		}
		//更新订单状态
		String rs = transactionService.procesNotifyTransaction(model);
		if(rs.equals(BusinessMessages.SUCCESS_MESSAGE)) {
			// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
			resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
					+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
		}
		return resXml;
	}
	
	/**
	 * @Title: processRequestToMap 
	 * @Description: 将Request转成Map
	 * @param @param request
	 * @param @return
	 * @param @throws IOException
	 * @param @throws UnsupportedEncodingException
	 * @param @throws JDOMException
	 * @return SortedMap<Object,Object>
	 * @throws
	 */
	private SortedMap<Object, Object> processRequestToMap(HttpServletRequest request)
			throws IOException, UnsupportedEncodingException, JDOMException {
		InputStream inputStream = request.getInputStream();
		StringBuffer sb = new StringBuffer();
		String s;
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream,Consts.CHARACTERE_NCODING_UTF8));
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();

		// 解析xml成map
		Map<String, String> m = new HashMap<String, String>();
		m = XMLUtil.doXMLParse(sb.toString());

		// 过滤空 设置 TreeMap
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		Iterator it = m.keySet().iterator();
		while (it.hasNext()) {
			String parameter = (String) it.next();
			String parameterValue = m.get(parameter);

			String v = "";
			if (null != parameterValue) {
				v = parameterValue.trim();
			}
			packageParams.put(parameter, v);
		}
		return packageParams;
	}
	
	/**
	 * @Title: commonParams 
	 * @Description: 基础参数
	 * @param @param packageParams
	 * @return void
	 * @throws
	 */
	public static void commonParams(SortedMap<Object, Object> packageParams) {
		// 账号信息
		String appid = wxBeanConfig.getAppId(); // appid
		String mch_id = wxBeanConfig.getMchId(); // 商业号
		// 生成随机字符串
		String currTime = PayCommonUtil.getCurrTime();
		String strTime = currTime.substring(8, currTime.length());
		String strRandom = PayCommonUtil.buildRandom(4) + "";
		String nonce_str = strTime + strRandom;
		packageParams.put("appid", appid);// 公众账号ID
		packageParams.put("mch_id", mch_id);// 商户号
		packageParams.put("nonce_str", nonce_str);// 随机字符串
	}

	/**
	 * @Title: shorturl 
	 * @Description: 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX)，减小二维码数据量，提升扫描速度和精确度
	 * @param @param urlCode
	 * @return void
	 * @throws
	 */
	@SuppressWarnings("rawtypes")
	public static void shorturl(String urlCode) {
		try {
			String key = wxBeanConfig.getApiKey();
			SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
			commonParams(packageParams);
			packageParams.put("long_url", urlCode);// URL链接
			String sign = PayCommonUtil.createSign("UTF-8", packageParams, key);
			packageParams.put("sign", sign);// 签名
			String requestXML = PayCommonUtil.getRequestXml(packageParams);
			String resXml = HttpUtil.postData(wxBeanConfig.getShortUrl(), requestXML);
			Map map = XMLUtil.doXMLParse(resXml);
			String returnCode = (String) map.get("return_code");
			if (Consts.SUCCESS_CAPITAL.equals(returnCode)) {
				String resultCode = (String) map.get("return_code");
				if (Consts.SUCCESS_CAPITAL.equals(resultCode)) {
					urlCode = (String) map.get("short_url");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
